package com.zonski.jbots.engine.test;

import junit.framework.TestCase;

import com.zonski.jbots.engine.Entity;
import com.zonski.jbots.engine.EntityType;
import com.zonski.jbots.engine.Rectangle;
import com.zonski.jbots.engine.Collision;
import com.zonski.jbots.engine.CollisionData;
import com.zonski.jbots.engine.CollisionDetector;
import com.zonski.jbots.engine.Directions;
import com.zonski.jbots.engine.collision.SlideCollisionEffect;

public class CollisionDetectorCollisionTestCase extends TestCase
{
    public CollisionDetectorCollisionTestCase(String name)
    {
        super(name);
    }
    
    public void testEastCollision()
    {
        Entity e1 = new Entity();
        e1.entityType = (EntityType.getEntityType("one"));
        e1.bounds = (new Rectangle(10, 10, 10, 10));
        e1.setVelocity(2, 0, 0, Entity.STARTING_STEPS);
        e1.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Entity e2 = new Entity();
        e2.entityType = (EntityType.getEntityType("two"));
        e2.bounds = (new Rectangle(21, 10, 10, 10));
        e2.setVelocity(0, 0, 0, Entity.STARTING_STEPS);
        e2.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Collision collision = CollisionDetector.getCollision(e1, getBounds(e1), e2, new Collision());
        CollisionData data1 = collision.getCollisionData(e1);
        CollisionData data2 = collision.getCollisionData(e2);
        this.assertEquals(21, data1.x);
        this.assertEquals(21, data2.x);
        this.assertEquals(Directions.EAST, data1.edge);
        this.assertEquals(Directions.WEST, data2.edge);
    }

    public void testWestCollision()
    {
        Entity e1 = new Entity();
        e1.entityType = (EntityType.getEntityType("one"));
        e1.bounds = (new Rectangle(10, 10, 10, 10));
        e1.setVelocity(0, 0, 0, Entity.STARTING_STEPS);
        e1.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Entity e2 = new Entity();
        e2.entityType = (EntityType.getEntityType("two"));
        e2.bounds = (new Rectangle(25, 10, 10, 10));
        e2.setVelocity(-10, 0, 0, Entity.STARTING_STEPS);
        e2.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Collision collision = CollisionDetector.getCollision(e1, getBounds(e1), e2, new Collision());
        CollisionData data1 = collision.getCollisionData(e1);
        CollisionData data2 = collision.getCollisionData(e2);
        this.assertEquals(20, data1.x);
        this.assertEquals(20, data2.x);
        this.assertEquals(Directions.EAST, data1.edge);
        this.assertEquals(Directions.WEST, data2.edge);
    }

    public void testSouthCollision()
    {
        Entity e1 = new Entity();
        e1.entityType = (EntityType.getEntityType("one"));
        e1.bounds = (new Rectangle(10, 10, 10, 10));
        e1.setVelocity(0, 20, 0, Entity.STARTING_STEPS);
        e1.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Entity e2 = new Entity();
        e2.entityType = (EntityType.getEntityType("two"));
        e2.bounds = (new Rectangle(10, 30, 10, 10));
        e2.setVelocity(0, 0, 0, Entity.STARTING_STEPS);
        e2.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Collision collision = CollisionDetector.getCollision(e1, getBounds(e1), e2, new Collision());
        CollisionData data1 = collision.getCollisionData(e1);
        CollisionData data2 = collision.getCollisionData(e2);
        this.assertEquals(30, data1.y);
        this.assertEquals(30, data2.y);
        this.assertEquals(Directions.SOUTH, data1.edge);
        this.assertEquals(Directions.NORTH, data2.edge);
    }


    public void testNorthCollision()
    {
        Entity e1 = new Entity();
        e1.entityType = (EntityType.getEntityType("one"));
        e1.bounds = (new Rectangle(10, 5, 10, 10));
        e1.setVelocity(0, 0, 0, Entity.STARTING_STEPS);
        e1.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Entity e2 = new Entity();
        e2.entityType = (EntityType.getEntityType("two"));
        e2.bounds = (new Rectangle(10, 20, 10, 10));
        e2.setVelocity(0, -10, 0, Entity.STARTING_STEPS);
        e2.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Collision collision = CollisionDetector.getCollision(e1, getBounds(e1), e2, new Collision());
        CollisionData data1 = collision.getCollisionData(e1);
        CollisionData data2 = collision.getCollisionData(e2);
        this.assertEquals(15, data1.y);
        this.assertEquals(15, data2.y);
        this.assertEquals(Directions.SOUTH, data1.edge);
        this.assertEquals(Directions.NORTH, data2.edge);
    }

    public void testNorthEastCollision()
    {
        Entity e1 = new Entity();
        e1.entityType = (EntityType.getEntityType("one"));
        e1.bounds = (new Rectangle(5, 5, 10, 10));
        e1.setVelocity(10, 10, 0, Entity.STARTING_STEPS);
        e1.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Entity e2 = new Entity();
        e2.entityType = (EntityType.getEntityType("two"));
        e2.bounds = (new Rectangle(5, 20, 50, 10));
        e2.setVelocity(0, 0, 0, Entity.STARTING_STEPS);
        e2.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Collision collision = CollisionDetector.getCollision(e1, getBounds(e1), e2, new Collision());
        CollisionData data1 = collision.getCollisionData(e1);
        CollisionData data2 = collision.getCollisionData(e2);
        this.assertEquals(20, data1.y);
        this.assertEquals(20, data2.y);
        this.assertEquals(20, data1.x);
        this.assertEquals(20, data2.x);
        this.assertEquals(Directions.SOUTH, data1.edge);
        this.assertEquals(Directions.NORTH, data2.edge);
    }

    public void testNorthWestCollision()
    {
        Entity e1 = new Entity();
        e1.entityType = (EntityType.getEntityType("one"));
        e1.bounds = (new Rectangle(5, 5, 10, 10));
        e1.setVelocity(-10, 10, 0, Entity.STARTING_STEPS);
        e1.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Entity e2 = new Entity();
        e2.entityType = (EntityType.getEntityType("two"));
        e2.bounds = (new Rectangle(-35, 20, 50, 10));
        e2.setVelocity(0, 0, 0, Entity.STARTING_STEPS);
        e2.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Collision collision = CollisionDetector.getCollision(e1, getBounds(e1), e2, new Collision());
        CollisionData data1 = collision.getCollisionData(e1);
        CollisionData data2 = collision.getCollisionData(e2);
        this.assertEquals(20, data1.y);
        this.assertEquals(20, data2.y);
        this.assertEquals(0, data1.x);
        this.assertEquals(0, data2.x);
        this.assertEquals(Directions.SOUTH, data1.edge);
        this.assertEquals(Directions.NORTH, data2.edge);
    }

    public void testSouthWestCollision()
    {
        Entity e1 = new Entity();
        e1.entityType = (EntityType.getEntityType("one"));
        e1.bounds = (new Rectangle(5, 5, 10, 10));
        e1.setVelocity(-10, -10, 0, Entity.STARTING_STEPS);
        e1.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Entity e2 = new Entity();
        e2.entityType = (EntityType.getEntityType("two"));
        e2.bounds = (new Rectangle(-40, -10, 50, 10));
        e2.setVelocity(0, 0, 0, Entity.STARTING_STEPS);
        e2.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Collision collision = CollisionDetector.getCollision(e1, getBounds(e1), e2, new Collision());
        CollisionData data1 = collision.getCollisionData(e1);
        CollisionData data2 = collision.getCollisionData(e2);
        this.assertEquals(0, data1.y);
        this.assertEquals(0, data2.y);
        this.assertEquals(0, data1.x);
        this.assertEquals(0, data2.x);
        this.assertEquals(Directions.NORTH, data1.edge);
        this.assertEquals(Directions.SOUTH, data2.edge);
    }


    public void testSouthEastCollision()
    {
        Entity e1 = new Entity();
        e1.bounds = (new Rectangle(5, 5, 10, 10));
        e1.setVelocity(10, -10, 0, Entity.STARTING_STEPS);
        e1.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Entity e2 = new Entity();
        e2.bounds = (new Rectangle(5, -10, 50, 10));
        e2.setVelocity(0, 0, 0, Entity.STARTING_STEPS);
        e2.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Collision collision = CollisionDetector.getCollision(e1, getBounds(e1), e2, new Collision());
        CollisionData data1 = collision.getCollisionData(e1);
        CollisionData data2 = collision.getCollisionData(e2);
        this.assertEquals(0, data1.y);
        this.assertEquals(0, data2.y);
        this.assertEquals(20, data1.x);
        this.assertEquals(20, data2.x);
        this.assertEquals(Directions.NORTH, data1.edge);
        this.assertEquals(Directions.SOUTH, data2.edge);
    }

    public void testOtherNorthEastCollision()
    {
        Entity e1 = new Entity();
        e1.bounds = (new Rectangle(5, 5, 10, 10));
        e1.setVelocity(10, 10, 0, Entity.STARTING_STEPS);
        e1.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Entity e2 = new Entity();
        e2.bounds = (new Rectangle(20, 5, 10, 50));
        e2.setVelocity(0, 0, 0, Entity.STARTING_STEPS);
        e2.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Collision collision = CollisionDetector.getCollision(e1, getBounds(e1), e2, new Collision());
        CollisionData data1 = collision.getCollisionData(e1);
        CollisionData data2 = collision.getCollisionData(e2);
        this.assertEquals(20, data1.y);
        this.assertEquals(20, data2.y);
        this.assertEquals(20, data1.x);
        this.assertEquals(20, data2.x);
        this.assertEquals(Directions.EAST, data1.edge);
        this.assertEquals(Directions.WEST, data2.edge);
    }

    public void testOtherNorthWestCollision()
    {
        Entity e1 = new Entity();
        e1.bounds = (new Rectangle(5, 5, 10, 10));
        e1.setVelocity(-10, 10, 0, Entity.STARTING_STEPS);
        e1.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Entity e2 = new Entity();
        e2.bounds = (new Rectangle(-10, 5, 10, 50));
        e2.setVelocity(0, 0, 0, Entity.STARTING_STEPS);
        e2.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Collision collision = CollisionDetector.getCollision(e1, getBounds(e1), e2, new Collision());
        CollisionData data1 = collision.getCollisionData(e1);
        CollisionData data2 = collision.getCollisionData(e2);
        this.assertEquals(20, data1.y);
        this.assertEquals(20, data2.y);
        this.assertEquals(0, data1.x);
        this.assertEquals(0, data2.x);
        this.assertEquals(Directions.WEST, data1.edge);
        this.assertEquals(Directions.EAST, data2.edge);
    }

    public void testOtherNorthEastBackEndCollision()
    {
        Entity e1 = new Entity();
        e1.bounds = (new Rectangle(5, 5, 10, 10));
        e1.setVelocity(10, 10, 0, Entity.STARTING_STEPS);
        e1.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Entity e2 = new Entity();
        e2.bounds = (new Rectangle(5, 15, 10, 10));
        e2.setVelocity(0, 0, 0, Entity.STARTING_STEPS);
        e2.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Collision collision = CollisionDetector.getCollision(e1, getBounds(e1), e2, new Collision());
        CollisionData data1 = collision.getCollisionData(e1);
        CollisionData data2 = collision.getCollisionData(e2);
        this.assertEquals(15, data1.y);
        this.assertEquals(15, data2.y);
        this.assertEquals(Directions.SOUTH, data1.edge);
        this.assertEquals(Directions.NORTH, data2.edge);
    }

    public void testOtherEastNorthBackEndCollision()
    {
        Entity e1 = new Entity();
        e1.bounds = (new Rectangle(5, 5, 10, 10));
        e1.setVelocity(10, 10, 0, Entity.STARTING_STEPS);
        e1.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Entity e2 = new Entity();
        e2.bounds = (new Rectangle(15, 5, 10, 10));
        e2.setVelocity(0, 0, 0, Entity.STARTING_STEPS);
        e2.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Collision collision = CollisionDetector.getCollision(e1, getBounds(e1), e2, new Collision());
        CollisionData data1 = collision.getCollisionData(e1);
        CollisionData data2 = collision.getCollisionData(e2);
        this.assertEquals(15, data1.x);
        this.assertEquals(15, data2.x);
        this.assertEquals(Directions.EAST, data1.edge);
        this.assertEquals(Directions.WEST, data2.edge);
    }

    public void testOtherNorthWestBackEndCollision()
    {
        Entity e1 = new Entity();
        e1.bounds = (new Rectangle(5, 5, 10, 10));
        e1.setVelocity(-10, 10, 0, Entity.STARTING_STEPS);
        e1.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Entity e2 = new Entity();
        e2.bounds = (new Rectangle(5, 15, 10, 10));
        e2.setVelocity(0, 0, 0, Entity.STARTING_STEPS);
        e2.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Collision collision = CollisionDetector.getCollision(e1, getBounds(e1), e2, new Collision());
        CollisionData data1 = collision.getCollisionData(e1);
        CollisionData data2 = collision.getCollisionData(e2);
        this.assertEquals(15, data1.y);
        this.assertEquals(15, data2.y);
        this.assertEquals(Directions.SOUTH, data1.edge);
        this.assertEquals(Directions.NORTH, data2.edge);
    }


    public void testOtherWestSouthBackEndCollision()
    {
        Entity e1 = new Entity();
        e1.bounds = (new Rectangle(5, 5, 10, 10));
        e1.setVelocity(-10, -10, 0, Entity.STARTING_STEPS);
        e1.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Entity e2 = new Entity();
        e2.bounds = (new Rectangle(-10, 5, 10, 10));
        e2.setVelocity(0, 0, 0, Entity.STARTING_STEPS);
        e2.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Collision collision = CollisionDetector.getCollision(e1, getBounds(e1), e2, new Collision());
        CollisionData data1 = collision.getCollisionData(e1);
        CollisionData data2 = collision.getCollisionData(e2);
        this.assertEquals(0, data1.x);
        this.assertEquals(0, data2.x);
        this.assertEquals(Directions.WEST, data1.edge);
        this.assertEquals(Directions.EAST, data2.edge);
    }

    // double movements
    
    public void testNorthMovingAwayCollision()
    {
        Entity e1 = new Entity();
        e1.bounds = (new Rectangle(5, 10, 10, 10));
        e1.setVelocity(0, 40, 0, Entity.STARTING_STEPS);
        e1.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Entity e2 = new Entity();
        e2.bounds = (new Rectangle(5, 30, 10, 10));
        e2.setVelocity(0, 20, 0, Entity.STARTING_STEPS);
        e2.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Collision collision = CollisionDetector.getCollision(e1, getBounds(e1), e2, new Collision());
        CollisionData data1 = collision.getCollisionData(e1);
        CollisionData data2 = collision.getCollisionData(e2);
        this.assertEquals(40, data1.y);
        this.assertEquals(40, data2.y);
        this.assertEquals(Directions.SOUTH, data1.edge);
        this.assertEquals(Directions.NORTH, data2.edge);
    }


    public void testNorthMovingTogetherCollision()
    {
        Entity e1 = new Entity();
        e1.bounds = (new Rectangle(5, 10, 10, 10));
        e1.setVelocity(0, 20, 0, Entity.STARTING_STEPS);
        e1.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Entity e2 = new Entity();
        e2.bounds = (new Rectangle(5, 30, 10, 10));
        e2.setVelocity(0, -20, 0, Entity.STARTING_STEPS);
        e2.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Collision collision = CollisionDetector.getCollision(e1, getBounds(e1), e2, new Collision());
        CollisionData data1 = collision.getCollisionData(e1);
        CollisionData data2 = collision.getCollisionData(e2);
        this.assertEquals(25, data1.y);
        this.assertEquals(25, data2.y);
        this.assertEquals(Directions.SOUTH, data1.edge);
        this.assertEquals(Directions.NORTH, data2.edge);
    }

    public void testWestMovingAwayCollision()
    {
        Entity e1 = new Entity();
        e1.bounds = (new Rectangle(10, 10, 10, 10));
        e1.setVelocity(40, 0, 0, Entity.STARTING_STEPS);
        e1.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Entity e2 = new Entity();
        e2.bounds = (new Rectangle(30, 10, 10, 10));
        e2.setVelocity(20, 0, 0, Entity.STARTING_STEPS);
        e2.collisionEffect = (SlideCollisionEffect.INSTANCE);

        Collision collision = CollisionDetector.getCollision(e1, getBounds(e1), e2, new Collision());
        CollisionData data1 = collision.getCollisionData(e1);
        CollisionData data2 = collision.getCollisionData(e2);
        this.assertEquals(40, data1.x);
        this.assertEquals(40, data2.x);
        this.assertEquals(Directions.EAST, data1.edge);
        this.assertEquals(Directions.WEST, data2.edge);
    }

    public Rectangle getBounds(Entity entity)
    {
        Rectangle result = new Rectangle(0, 0, 0, 0);
        Rectangle.expand(entity.bounds, entity.xVelocity, entity.yVelocity, result);
        return result;
    }
}
